package com.rwb.util;

import com.rwb.exception.ExcelException;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by ruwenbo on 2017/12/17.
 */
public class ExcelUtil {

    private ExcelUtil() {

    }

    /**
     * @MethodName  : listToExcel
     * @Description : 导出Excel（可以导出到本地文件系统，也可以导出到浏览器，可自定义工作表大小）
     * @param list      数据源
     * @param fieldMap      类的英文属性和Excel中的中文列名的对应关系
     * 如果需要的是引用对象的属性，则英文属性使用类似于EL表达式的格式
     * 如：list中存放的都是student，student中又有college属性，而我们需要学院名称，则可以这样写
     * fieldMap.put("college.collegeName","学院名称")
     * @param sheetName 工作表的名称
     * @param sheetSize 每个工作表中记录的最大个数
     * @param out       导出流
     * @throws ExcelException
     */
    public static <T>  void   listToExcel (
            List<T> list ,
            LinkedHashMap<String,String> fieldMap,
            String sheetName,
            int sheetSize,
            OutputStream out
    ) throws ExcelException {

        if (null == list || list.size() == 0) {
            throw new ExcelException("数据源中没有数据");
        }

        if (sheetSize > 65535 || sheetSize < 1) {
            sheetSize = 65535;
        }

        // 创建工作潽并发送到outputstream指定的位置
        HSSFWorkbook workbook;
        try {

            workbook = new HSSFWorkbook();
            //因为2003的Excel一个工作表最多可以有65536条记录，除去列头剩下65535条
            //所以如果记录太多，需要放到多个工作表中，其实就是个分页的过程
            //1.计算一共有多少个工作表
            double sheetNum = Math.ceil(list.size() / new Integer(sheetSize).doubleValue());

            // 2.创建相应的工作噗,并向其中添加数据
            for (int i = 0; i < sheetNum; i++) {
                // 如果只有一个工作噗
                if (1 == sheetNum) {
                    HSSFSheet sheet = workbook.createSheet();
                    fillSheet(sheet, list, fieldMap, 0, list.size() - 1);
                }
                // 如果有多个工作噗
                else {
                    HSSFSheet sheet = workbook.createSheet();
                    // 获取开始与结束索引
                    int firstIndex=i*sheetSize;
                    int lastIndex=(i+1)*sheetSize-1>list.size()-1 ? list.size()-1 : (i+1)*sheetSize-1;
                    fillSheet(sheet, list, fieldMap, 0, list.size() - 1);
                }
            }
            workbook.write(out);
        } catch (Exception e) {
            e.printStackTrace();
            if (e instanceof  ExcelException) {
                //如果是ExcelException，则直接抛出
                throw (ExcelException) e;
                //否则将其它异常包装成ExcelException再抛出
            } else {
                throw new ExcelException("导出Excel失败");
            }
        }
    }

    /**
     * @MethodName  : fillSheet
     * @Description : 向工作表中填充数据
     * @param sheet     工作表
     * @param list  数据源
     * @param fieldMap 中英文字段对应关系的Map
     * @param firstIndex    开始索引
     * @param lastIndex 结束索引
     */
    private static <T> void fillSheet(HSSFSheet sheet, List<T> list,
                                      LinkedHashMap<String, String> fieldMap, int firstIndex, int lastIndex) throws NoSuchFieldException, IllegalAccessException {

        //定义存放英文字段名和中文字段名的数组
        String[] enFields = new String[fieldMap.size()];
        String[] cnFields = new String[fieldMap.size()];

        // 填充数组
        int count = 0;
        for (Map.Entry<String, String> entry : fieldMap.entrySet()) {
            enFields[count] = entry.getKey();
            cnFields[count] = entry.getValue();
            count++;
        }
        // 填充表头
        HSSFRow row = sheet.createRow(0);
        for (int i = 0; i < cnFields.length; i++) {
            HSSFCell cell = row.createCell(i);
            cell.setCellValue(cnFields[i]);
        }
        // 填充内容
        int rowNum = 1;
        for (int index = firstIndex; index < lastIndex; index++) {
            T item = list.get(index);
            row = sheet.createRow(rowNum);
            for (int j = 0; j < cnFields.length; j++) {
                Field field = item.getClass().getDeclaredField(enFields[j]);
                field.setAccessible(true);
                Object obj = field.get(item);
                String value = obj == null ? "" : obj.toString();
                HSSFCell cell = row.createCell(j);
                cell.setCellValue(value);
            }
            rowNum++;
        }
    }
}
